package com.stud.seckill.controller;

import com.alibaba.fastjson.JSON;
import com.stud.seckill.common.auth.UserContext;
import com.stud.seckill.common.config.*;
import com.stud.seckill.common.enums.CacheKeyEnum;
import com.stud.seckill.entity.vo.UserOrderDTO;
import com.stud.seckill.entity.*;
import com.stud.seckill.service.GoodsService;
import com.stud.seckill.service.OrderService;
import com.stud.seckill.service.SeckillGoodsService;
import com.stud.seckill.service.SeckillOrderService;
import com.stud.seckill.common.vo.R;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("/seckill")
public class SeckillController implements InitializingBean {

    @Autowired
    private GoodsService goodsService;
    @Autowired
    private SeckillGoodsService seckillGoodsService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private SeckillOrderService seckillOrderService;
    @Autowired
    private CacheService cacheService;
    @Resource
    private RedisScript<Long> stockScript;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    // 库存标记
    private static boolean isHasSign = true;
    private final Map<Long, Boolean> emptyStockSign = new HashMap<>();

    /**
     * 第一次压测 QPS 435、625
     *
     * 加入数据缓存 QPS 2800、1500
     *
     * 加上内存标记
     *
     * @param model
     * @param goodsId
     * @return
     */
    // @AccessLimit(second = 6, maxCount = 6)
    @PostMapping("/doSeckill")
    public String doSeckill(Model model, @RequestParam Long goodsId) {

        UserEntity user = UserContext.getUser();
        if (user == null) {
            model.addAttribute("errMsg", "请去登录");
            return "secKillFail";
        }

        if (!isHasSign) {
            // 扣减数据失败的计数
            cacheService.set(CacheKeyEnum.秒杀商品, "storeMark:userId" + user.getId()+"goodsId"+goodsId, 1);
            model.addAttribute("errMsg", "秒杀失败了2");
            return "secKillFail";
        }

        // 判断库存
        SeckillGoodsEntity seckillGoods = seckillGoodsService.get(goodsId);
        if (seckillGoods.getStockCount() < 1) {
            isHasSign = false;
            // 扣减数据失败的计数
            cacheService.set(CacheKeyEnum.秒杀商品, "storeFail:userId" + user.getId()+"goodsId"+goodsId, 1);
            model.addAttribute("errMsg", "秒杀失败了1");
            return "secKillFail";
        }

        // 判断是否重复抢购
        Boolean isHasOrder = cacheService.hasKey(CacheKeyEnum.秒杀订单, "userId"+user.getId()+"goodsId"+goodsId);
        if (isHasOrder) {
            // 扣减数据失败的计数
            cacheService.set(CacheKeyEnum.秒杀商品, "orderDup:userId" + user.getId()+"goodsId"+goodsId, 1);
            model.addAttribute("errMsg", "该商品每人限购一件");
            return "secKillFail";
        }

        // 生成订单
        OrderEntity order = seckillOrderService.saveOrder(user.getId(), goodsId);
        GoodsEntity goods = goodsService.get(goodsId);

        model.addAttribute("order", order);
        model.addAttribute("goods", goods);
        return "orderDetail";
    }

    /**
     * 静态版秒杀
     *
     * 第一次压测 QPS 1800
     *
     *
     * @param goodsId
     * @return
     */
    @ResponseBody
    @PostMapping("/doSeckill2")
    public R<OrderEntity> doSeckill2(@RequestParam Long goodsId) {
        UserEntity user = UserContext.getUser();
        if (user == null) {
            return R.fail("未登录");
        }

        if (emptyStockSign.get(goodsId)) {
            // 扣减数据失败的计数
            cacheService.set(CacheKeyEnum.秒杀监控数据, "storeSign:userId" + user.getId()+"goodsId"+goodsId, 1);
            return R.fail("秒杀失败了");
        }

        // 判断库存
        /*SeckillGoodsEntity seckillGoods = seckillGoodsService.get(goodsId);
        if (seckillGoods.getStockCount() < 1) {
            emptyStockSign.put(goodsId, true);
            // 扣减数据失败的计数
            cacheService.set(CacheKeyEnum.监控数据, "storeFail:userId" + user.getId()+"goodsId"+goodsId, 1);
            return R.fail("秒杀失败了");
        }*/

        // 库存从缓存扣
        Long isR = redisTemplate.execute(stockScript, Collections.singletonList(CacheKeyEnum.秒杀商品.getKey() + "store:" + goodsId));
        if (isR == null || isR == 0) {
            emptyStockSign.put(goodsId, true);
            // 扣减数据失败的计数
            cacheService.set(CacheKeyEnum.秒杀监控数据, "storeFail:userId" + user.getId()+"goodsId"+goodsId, 1);
            return R.fail("秒杀失败了");
        }

        // 判断是否重复抢购
        Boolean isHasOrder = cacheService.hasKey(CacheKeyEnum.秒杀监控数据, "orderSuc:userId"+user.getId()+"goodsId"+goodsId);
        if (isHasOrder) {
            // 扣减数据失败的计数
            cacheService.set(CacheKeyEnum.秒杀监控数据, "orderDup:userId" + user.getId()+"goodsId"+goodsId, 1);
            return R.fail("该商品每人限购一件");
        }

        cacheService.set(CacheKeyEnum.秒杀监控数据, "orderSuc:userId"+user.getId()+"goodsId"+goodsId, 1);

        UserOrderDTO params = new UserOrderDTO();
        params.setUserId(user.getId());
        params.setGoodsId(goodsId);
        rabbitTemplate.convertAndSend("seckillOrder", JSON.toJSONString(params));

        // 生成订单 - 改成异步，无需直接下单
        // OrderEntity orderEntity = seckillOrderService.saveOrder(user.getId(), goodsId);
        // return R.success(orderEntity);
        return R.success();
    }

    /**
     *
     * @param goodsId
     * @return
     */
    @ResponseBody
    @GetMapping("/getResult")
    public R<?> getResult(@RequestParam Long goodsId) {
        UserEntity user = UserContext.getUser();
        if (user == null) {
            return R.fail("未登录");
        }
        Long orderId = seckillOrderService.getResult(user.getId(), goodsId);
        return R.success(orderId);
    }

    /**
     * 10秒内，同一个用户只准访问一次。
     * 压测试下能不能防并发
     * @return
     */
    // @AccessLimit(second = 10, maxCount = 1, needLogin = false)
    @ResponseBody
    @PostMapping("/doSeckill3")
    public R<?> doSeckill3(Integer goodsId) {
        /*if (!lockService.lock("lock:doSeckill:"+goodsId, Thread.currentThread().getName(), 10)) {
            cacheService.increment(CacheKeyEnum.秒杀商品, "fail" + goodsId);
            return R.fail("请等待");
        }*/
        System.out.println("doSeckill" + goodsId);
        cacheService.increment(CacheKeyEnum.秒杀商品, "success" + goodsId);
        return R.success();
    }

    @Override
    public void afterPropertiesSet() {
        // 秒杀数据初始化
        // init();
    }

    /**
     * 初始化库存和订单
     */
    public void init() {
        goodsService.initStock();
        seckillGoodsService.initStock();
        orderService.initOrder();
        seckillOrderService.initOrder();

        List<SeckillGoodsEntity> goodsEntityList = seckillGoodsService.selectList(null);
        for (SeckillGoodsEntity goods : goodsEntityList) {
            // 内存标记
            emptyStockSign.put(goods.getId(), false);
            // 缓存库存
            cacheService.set(CacheKeyEnum.秒杀商品, "store:" + goods.getId(), goods.getStockCount());
        }
    }

}
